数据结构-----后序遍历二叉树非递归算法(利用堆栈实现)

一、非递归后序遍历算法思想

        后序遍历的非递归算法中节点的进栈次数是两个,即每个节点都要进栈两次,第二次退栈的时候才访问节点。

第一次进栈时,在遍历左子树的过程中将"根"节点进栈,待左子树访问完后,回溯的节点退栈,即退出这个"根"节点,但不能立即访问,只能借助于这个"根"去找该"根"的右子树,并遍历这棵右子树,直到该右子树全部遍历以后,再退出该"根"节点,并访问它。

           所以为了记录节点是第一次还是第二次进栈,就在堆栈数据元素的结构中增加一个数据项:进栈标志。

                 (1)当节点非空时或堆栈非空时,执行(2),否则结束算法;

           (2)当节点指针非空时,节点的进栈标志设为false,节点指针及进栈标志进栈,然后将节点指向进栈节点的左子树的根,重复(2),知道指针为空(最后一个进栈的是最左子树),节点指针为空时,转(3);

           (3)堆栈非空时,从堆栈中退出一个节点的指针。如果退出的节点的进栈标志为true,说明该节点是第二次退栈,访问该接点,并将指针强制设为空,准备下一次退栈,并转(3),如果进栈标志为false,说明该节点是第一次退栈,将进栈标志设为true,然后将该节点指针及进栈标志进栈,再将指针指向它的右子树,转(1)。

二、代码实现

#include<stdio.h>
#include<stdlib.h>

typedef char EType; 

struct BinaryTreeNode
{
	EType data;
	struct BinaryTreeNode *LChild;
	struct BinaryTreeNode *RChild;
};
typedef BinaryTreeNode BinaryTree;

typedef struct SType
{
	BinaryTreeNode *ptr;
	bool status;//进栈标志
}SType;

typedef struct Stack
{
	SType *element;
	int top;
	int MaxSize;
}Stack;

void CreatStack(Stack &S,int MaxStackSize);
bool IsEmpty(Stack &S);
bool IsFull(Stack &S);
bool GetTop(Stack &S,SType &result);
bool Pop(Stack &S,SType &result);
bool Push(Stack &S,SType &x);
void CreatBiTree(BinaryTreeNode **BT);
void PostOrderNoRecursive(BinaryTreeNode *BT);

int main()
{
    BinaryTreeNode *BT = NULL;
	CreatBiTree(&BT);
	printf("后序遍历二叉树非递归算法输出为:");
	PostOrderNoRecursive(BT);
	printf("\n");
	return 0;
}

void CreatStack(Stack &S,int MaxStackSize)
{
	S.MaxSize = MaxStackSize;
	S.element = new SType[S.MaxSize];
	S.top = -1;
}

bool IsEmpty(Stack &S)
{
	if(S.top == -1)
		return true;
	return false;
}

bool IsFull(Stack &S)
{
	if(S.top >= S.MaxSize-1)
		return true;
	return false;
}

bool GetTop(Stack &S,SType &result)
{
	if(IsEmpty(S))
		return false;
	result = S.element[S.top];
	return true;
}

bool Pop(Stack &S,SType &result)
{
	if(IsEmpty(S))
		return false;
	result = S.element[S.top];
	S.top--;
	return true;
}

bool Push(Stack &S,SType &x)
{
    if(IsFull(S))
		return false;
	S.top++;
	S.element[S.top] = x;
	return true;
}

void CreatBiTree(BinaryTreeNode **BT)
{
	EType tem;
	
	scanf("%c",&tem);
	if(' ' == tem)
	{
	    *BT = NULL;
	}
	else
	{
		*BT = new BinaryTreeNode;
		(*BT)->data = tem;
		CreatBiTree(&(*BT)->LChild);
        CreatBiTree(&(*BT)->RChild);
	}
}

void PostOrderNoRecursive(BinaryTreeNode *BT)
{
	Stack S;
	SType temp;
	BinaryTreeNode *p = BT;
	int MaxStackSize = 50;
	CreatStack(S,MaxStackSize);

	while(p || !IsEmpty(S))
	{
		if(p)//找最左子树
		{
			temp.status = false;//设置该节点是第一次进栈
			temp.ptr = p;
			Push(S,temp);
			p = p->LChild;
		}
		else
		{
			if(!IsEmpty(S))
			{
				Pop(S,temp);
				p = temp.ptr;
				if(temp.status)//若该节点是第二次退栈,就访问,并设置p=0继续退栈
				{
                    printf("%c\t",p->data);
					p = NULL;
				}	
			    else
				{
					temp.status = true;//设置该节点是第二次进栈
					Push(S,temp);
					p = p->RChild;//遍历该节点的右子树
				}
			}
		}
	}
}

三、 效果展示

建立这样一颗二叉树


所以按照前序遍历输入应该是:“AB_D_ _CE_ _ _”(其中“_”代表空格)

那么运行结果为:


  • 10
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
前序遍历(Preorder Traversal)是一种二叉树遍历方式,其顺序为:根节点 -> 左子树 -> 右子树。对于完全二叉树,我们可以通过非递归的方式来实现前序遍历非递归算法通常使用栈(Stack)来实现。这是因为栈是一种后入先出(LIFO)的数据结构,可以用来模拟递归的堆栈退栈过程。 以下是使用Python实现完全二叉树前序遍历非递归算法: ```python class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None def preorder_traversal(root): res = [] stack = [root] while stack: node = stack.pop() if node: res.append(node.val) # 由于是完全二叉树,所以左子节点只可能在根节点的左子树中存在,所以需要跳过根节点的右子树和空节点 if node.left: stack.append(node.left) if node.right and node != root: # 跳过根节点右子树中的空节点 stack.append(node.right) return res ``` 在这个算法中,我们首先创建一个栈并将根节点放入栈中。然后,我们进入一个循环,该循环会持续到栈为空为止。在每次循环中,我们从栈顶弹出一个节点,并将其值添加到结果列表中。然后,我们将该节点的左子节点(如果存在)放入栈中,如果该节点有右子节点且不是根节点(即不是空节点),那么也将右子节点放入栈中。这是因为完全二叉树的特性使得我们只需要遍历非空节点的左子树和对应的右子树即可。 这个算法的时间复杂度是O(n),其中n是二叉树的节点数,因为我们最多只需要访问每个节点一次。空间复杂度也是O(n),因为我们需要使用一个栈来存储节点。尽管看起来我们创建了一个临时列表来存储结果,但这只是一个方便我们输出的操作,不会额外占用空间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值